package com.ht.db.router.core;

import com.ht.db.router.config.DBRouterProperties;
import com.ht.db.router.support.DBContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class DBRouterStrategyHandler {

    private final DBRouterProperties dbRouterProperties;

    public DBRouterStrategyHandler(DBRouterProperties dbRouterProperties) {
        this.dbRouterProperties = dbRouterProperties;
    }

    /**
     * 社会分库属性
     */
    public void doRouter(String dbKeyValue) {
        int size = dbRouterProperties.getDbCount() * dbRouterProperties.getTbCount();
        // 扰动函数；在 JDK 的 HashMap 中，对于一个元素的存放，需要进行哈希散列。而为了让散列更加均匀，所以添加了扰动函数。扩展学习；https://mp.weixin.qq.com/s/CySTVqEDK9-K1MRUwBKRCg
        int idx = (size - 1) & (dbKeyValue.hashCode() ^ (dbKeyValue.hashCode() >>> 16));
        // 库表索引；相当于是把一个长条的桶，切割成段，对应分库分表中的库编号和表编号
        int dbIdx = idx / dbRouterProperties.getTbCount() + 1;
        int tbIdx = idx - dbRouterProperties.getTbCount() * (dbIdx - 1);
        // 设置到 ThreadLocal；关于 ThreadLocal 的使用场景和源码介绍；https://bugstack.cn/md/java/interview/2020-09-23-%E9%9D%A2%E7%BB%8F%E6%89%8B%E5%86%8C%20%C2%B7%20%E7%AC%AC12%E7%AF%87%E3%80%8A%E9%9D%A2%E8%AF%95%E5%AE%98%EF%BC%8CThreadLocal%20%E4%BD%A0%E8%A6%81%E8%BF%99%E4%B9%88%E9%97%AE%EF%BC%8C%E6%88%91%E5%B0%B1%E6%8C%82%E4%BA%86%EF%BC%81%E3%80%8B.html
        DBContextHolder.setDbKey(String.format("%02d", dbIdx));
        DBContextHolder.setTbKey(String.format("%03d", tbIdx));
        log.debug("数据库路由 dbIdx：{} tbIdx：{}", dbIdx, tbIdx);
    }

    /**
     * 清空分库属性
     */
    public void clear() {
        DBContextHolder.clearDbKey();
        DBContextHolder.clearTbKey();
    }
}
